# -*- mode: python -*-
###
#
# (c) 2000-2007 Wijnand Modderman <wijnand at tehmaze dot com>
# All rights reserved. See docs/LICENSE
#
###

"""
Online documentation, module search functionality.
"""

__revision__ = '$Hg: core.py,v a2b146bfced3 2007/01/20 14:14:46 +0100 $'

# system imports
import fnmatch
import os
import popen2
import sys
import threading
import time

# DDB imports
from ddb.log import log
from ddb.lang import lang
from ddb.user import userRegister
from ddb.settings import *
from ddb.tools import syntax, shell
from ddb.threads import locked, threaded
from ddb.access import access

# Twisted imports
try:
    from twisted import version as tversion
    twisted_version = tversion.short()
except ImportError:
    try:
        from twisted import __version__ as twisted_version
    except:
        twisted_version = 'unknown'

# DDB exports
EXPORT = ['Core', 'List', 'Help']

class Core:
    ALIAS = {
        'bug':  'bugs',
        'time': 'date',
        'v':    'version',
    }

    def date(self, event):
        """-

        Shows the current date and time."""
        event.reply(time.strftime('today it is %A %d %B %Y %I:%M:%S %p %Z, week %V'))

    @access('n', 'n')
    def cc(self, event):
        """[<prefix>]

        Set the command trigger to the specified prefix."""
        if not hasattr(event, 'commandRegister'):
            return
        if not event.transport.usePrefix:
            return event.reply('This transport does not support prefix characters.')
        if not event.args:
            return event.reply(syntax())
        ctx = [event.transport.type, event.transport.name, event.target.lower()]
        event.commandRegister.set('prefix', event.args, *ctx)
        event.reply('Command prefix set to: %s' % event.args)

    def bugs(self, event):
        event.reply('Please submit your bug reports at %s' % URL_BUGS)

    def lag(self, event):
        """-

        Show the current lag to the server."""
        if hasattr(event.transport, 'serverName'):
            name = event.transport.serverName
        else:
            name = 'server'
        if event.transport.lag:
            event.reply('%fs lag to %s' % (event.transport.lag, name))
        else:
            event.reply('no lag to %s' % name)

    @threaded
    def version(self, event):
        """-

        Shows the current version of the bot."""
        if os.path.isdir('.hg'):
            DDB_CODENAME = 'DEVEL-HG %s' % self._versionHg()
        event.reply('DDB version %s %s running on platform %s, python %s, twisted %s' % \
            (DDB_VERSION, DDB_CODENAME, sys.platform, sys.version.split('\n')[0].strip(),
            twisted_version))

    def _versionHg(self):
        (r, w, e) = popen2.popen3('hg tip')
        a = e.readlines()
        e.close()
        if a:
            w.close()
            r.close()
            return 'revision unknown'
        else:
            revision = r.readlines()[0].split(':')[1].strip()
            r.close()
            w.close()
            return 'revision %s' % revision

    @threaded
    def ps(self, event):
        """-

        Shows the current process status"""
        v = sys.version.replace('\r','').replace('\n','')
        if not os.name in ['posix'] or 'cygming' in v:
            event.reply('my platform (%s) can\'t do ps' % os.name)
            return
        (r, w, e) = popen2.popen3('ps wwup ' + str(os.getpid()))
        a = e.readlines()
        e.close()
        if a:
            event.reply(join(a))
            w.close()
            r.close()
        else:
            psInfo = r.readlines()
            r.close()
            w.close()
            f = str(psInfo[1]).strip().split()
            #bot.reply(str(f))
            if len(f) < 10:
                return
            d = "cpu=%s mem=%s vsz=%s rss=%s " % tuple(f[2:6])
            e = "stat=%s started=%s time=%s" % tuple(f[7:10])
            f = " threads=%s" % str(threading.activeCount())
            event.reply(d+e+f)

class Help:
    def _strip(self, str):
        while '  ' in str:
            str = str.replace('  ', ' ')
        return str.strip()

    def help(self, event, onlySyntax=False):
        """[<commando>]

        Shows you help on <commando>.

        If you wish to see an overview of available commandos, use the "apro" or 
        "list" commando."""
        if not event.args:
            event.args = 'help'
        docs = event.commands.doc(event.args)
        if docs and not None in docs:
            for doc in docs:
                if 'is an alias for' in doc:
                    alias = doc.split()[-1]
                    event.args = '%s\x02 is an alias: \x02%s' % (event.args, alias)
                else:
                    doc     = [self._strip(x) for x in doc.splitlines()]
                    reply = doc.pop(0)
                    if onlySyntax:
                        return event.reply('\x02%s\x02 %s' % (event.args, reply))
                    if doc:
                        if event.transport.multiLine:
                            if hasattr(event.transport, 'delimiter'):
                                delimiter = event.transport.delimiter
                            else:
                                delimiter = '\n'
                            reply = '\x02%s\x02 %s%s%s%s' % (event.args, reply, delimiter, delimiter,
                                delimiter.join(doc).strip())
                        else:
                            reply = '\x02%s\x02 %s -- %s' % (event.args, reply, ' '.join(doc).strip())
                    event.reply(reply)
        else:
            event.reply('No documentation found for "%s"' % event.args)

    def syntax(self, event):
        """[<command>]

        Show the syntax of the specified commando."""
        self.help(event, True)

class List:

    ALIAS={
        'list': 'apro'
        }

    def apro(self, event):
        """[<-m>] [<filter>]

        Shows all commands that match <filter>. If you specify <-m>, also
        list what modules they are in.

        <filter> supports glob characters. So use "*" to match all."""
        # check for filter
        withModule = False
        filter     = event.args
        if '-m' in filter.split(' '):
            withModule = True
            filter     = filter.split(' ')
            if filter:
                filter.remove('-m')
                filter = ' '.join(filter)
        if not filter:
            event.reply(syntax())
            return
        if not '*' in filter and not '?' in filter:
            filter = '*%s*' % filter
        # scan all hooks
        commands = {}
        for module in event.commands.register.keys():
            commands[module] = [x for x in event.commands.register[module].keys() if fnmatch.fnmatch(x, filter)]
            if commands[module]:
                for i in range(0, len(commands[module])):
                    aliases = []
                    x = commands[module][i]
                    if x in event.commands.aliases.values():
                        for alias in event.commands.aliases.keys():
                            if event.commands.aliases[alias] == x:
                                aliases.append(alias)
                    if aliases:
                        commands[module][i] = '%s (%s)' % (x, ', '.join(aliases))
                commands[module].sort()
                commands[module] = ', '.join(commands[module])
            else:
                del commands[module]
        commands = commands.items()
        commands.sort()
        # form reply
        reply = []
        if withModule:
            for x, y in commands:
                reply.append('\x02%s\x02: %s' % (x, y))
        else:
            for x, y in commands:
                reply.append(y)
            reply.sort()
        if len(reply):
            event.reply('matches for filter "%s": %s' % (filter, ', '.join(reply)))
        else:
            event.reply('no matches for filter "%s"' % filter)


class Mode:
    @access('o', 'o')
    def op(self, event):
        """-

        Gives you operator status on the current channel."""
        event.reply('whheee')
        if hasattr(event.callback, 'mode') and hasattr(event, 'nick'):
            victims = [event.nick]
            if event.args:
                victims = event.args.split()
            getattr(event.callback, 'op')(event.target, victims)
        else:
            event.reply('this input is not capable of setting modes')

import os
got_hg = os.path.isdir('.hg')

if got_hg:
    EXPORT.append('Update')
    class Update:
        @access('n', 'n')
        def update(self, event):
            """-

            Updates the code from repository."""
            hg_pull = shell('hg pull').strip()
            if 'no changes found' in hg_pull:
                event.reply('No changes found')
            hg_update = shell('hg update').strip()
            event.reply(hg_update)

# vim:ts=4:sw=4:et:
